#include "usart1.h"
#include "sys.h"
#include "led.h"
#include "volleyball.h"

const uint16_t CMD_HEAD = 0xAA55;
volatile uint16_t RxMsgBackup = 0;
volatile uint8_t NewMsgFlag = 0;
volatile uint8_t RxBuf[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
volatile uint8_t TxBuf[5] = {(uint8_t)CMD_HEAD, (uint8_t)CMD_HEAD >> 8, 0x00, 0x00, 0x00};

uint16_t *const TxCmdHead = (uint16_t *)TxBuf;
uint8_t *const TxCmdID = (uint8_t *)(&TxBuf[2]);
uint16_t *const TxCmdData = (uint16_t *)(&TxBuf[3]);
uint16_t *const RxCmdHead = (uint16_t *)RxBuf;
uint8_t *const RxCmdID = (uint8_t *)(&RxBuf[2]);
uint16_t *const RxCmdData = (uint16_t *)(&RxBuf[3]);

void usart1_init_without_IRQ(uint32_t bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    NVIC_SetPriority(USART1_IRQn, 0);
    NVIC_EnableIRQ(USART1_IRQn);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    IO_RS485_R0T1 = 0;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    USART_DeInit(USART1);
    USART_InitStructure.USART_BaudRate = bound;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);
}

void usart1_init_with_RXNE(uint32_t bound)
{
    // 变量初始化
    *TxCmdHead = CMD_HEAD;
    // 波特率初始化
    usart1_init_without_IRQ(bound);
    // RXNE中断初始化
    NVIC_SetPriority(USART1_IRQn, 0);              // 最高优先级
    NVIC_EnableIRQ(USART1_IRQn);                   // 使能中断
    USART_ClearFlag(USART1, USART_FLAG_RXNE);      // 清标志
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能RXNE中断
}

uint32_t usart1_read_data(uint8_t *buf, uint32_t data_size, uint32_t timeoutms)
{
    // 没收到返回0
    uint32_t nbytes_received = 0;
    uint32_t n_ms = 0;
    // 收字节
    while (n_ms < timeoutms)
    {
        add_1_per_1ms(&n_ms);
        if (USART1->SR & USART_FLAG_RXNE)
        {
            *buf++ = USART1->DR;
            nbytes_received++;
            if (nbytes_received == data_size)
            {
                break;
            }
        }
    }
    return nbytes_received;
}

// 通过DMA向USART1写入命令，启动从机扫描并返回数据， USART1连接到了RS485
void usart1_transmit_data_by_485(uint8_t *CmdBuf, uint8_t CmdSize)
{
    IO_RS485_R0T1 = 1;
    while (CmdSize--)
    {
        while ((USART1->SR & USART_FLAG_TXE) == (uint16_t)RESET)
        {
        }
        USART1->DR = *CmdBuf++;
    }
    while ((USART1->SR & USART_FLAG_TC) == (uint16_t)RESET)
    {
    }
    // 当时钟AHB为216M时，这里要人为延时两条指令，才不会出现IO_RS485_RT=0时，串口接收会拉低50ns
    // 后来认为是RX没有人为拉高的结果，在IO口设置中加了上拉
    // IO_RS485_R0T1 = 1;
    // IO_RS485_R0T1 = 1;
    IO_RS485_R0T1 = 0;
}

void usart1_transmit_curtain_cmd()
{
    uint8_t i = 0;
    IO_RS485_R0T1 = 1;
    while (i < 5)
    {
        while ((USART1->SR & USART_FLAG_TXE) == (uint16_t)RESET)
        {
        }
        // 当这个位置进入中断时，耽误了一些时间，再次写入DR不会将TC标置写为0，会导致最后一个字节发送不出去
        USART1->SR &= ~USART_FLAG_TC;
        USART1->DR = TxBuf[i++];
    }
    while ((USART1->SR & USART_FLAG_TC) == (uint16_t)RESET)
    {
    }
    // 当时钟AHB为216M时，这里要人为延时两条指令，才不会出现IO_RS485_RT=0时，串口接收会拉低50ns,
    // 后来设置将串口接收设置为接收拉高。这个问题没有了
    // IO_RS485_R0T1 = 1;
    // IO_RS485_R0T1 = 1;
    // Delay_us(2);
    IO_RS485_R0T1 = 0;
}

void USART1_IRQHandler(void)
{
    *(uint32_t *)RxBuf = *(uint32_t *)&RxBuf[1];
    (void)USART1->SR;
    RxBuf[4] = USART1->DR;

    if ((*RxCmdHead == CMD_HEAD))
    {
        RxMsgBackup = *RxCmdData;
        NewMsgFlag = 1;
        *(uint32_t *)(&RxBuf[1]) = 0x00;
    }
}

/* 老五米三向设计通读协议时没有用到停止位，波特率是4715，每一位213微秒，
   但向DR写入信息后，要等一位才会发送，所以是213*10微秒
   后改为213*9是因为原来的手工协议没有给停止位时间，*10也不会出大问题*/
void USART1_SendMsg_By_485_Without_Stopbit(uint8_t data)
{
    usart1_clear_all_flag();
    IO_RS485_R0T1 = 1;
    USART1->DR = data;
    Delay_us(213 * 10);
    IO_RS485_R0T1 = 0;
}

void USART1_Detect_baudrate()
{
}